查看原文
其他

如何不增加其他小伙伴工作量,进行业务解耦?

Java之间 2020-10-17

点击上方Java之间”,选择“置顶或者星标”

你关注的就是我关心的!

作者:老顾聊技术

前言

现在的项目都是多人进行协作开发,小到2-3人,大到几百人一起完成一个系统。团队间的沟通成本是整个项目中耗时比较长的,而且会经常遇到信息不对称问题,互相理解不一致问题,这个是我们管理者最头疼的。作为好的系统架构,也要考虑到沟通频率和业务耦合问题,尽量要把各个业务进行切分,进行解耦,这样减少了团队之间的无谓的沟通,让开发人员专注于自身的业务。老顾今天介绍一下单应用的业务解耦方案。

需求背景

现在我们面临一个需求: 我需要在用户注册成功的时候,根据用户提交的邮箱、手机号信息,向用户发送邮箱认证和手机号短信通知。传统的做法之一是在我们的UserService层注入邮件发送和短信发送的相关类,然后在完成用户注册同时,调用对应类方法完成邮件发送和短信发送,伪代码如下:

但这样做的话,会把我们邮件、短信发送的业务与我们的UserService的逻辑业务耦合在了一起。耦合造成的常见缺点是,我(甚至假设很频繁的)修改了邮件、短信发送的API,我就可能需要在UserService层修改相应的调用方法,但这样做人家UserService就会很无辜并吐槽:你改邮件、短信发送的业务,又不关我的事,干嘛老改到我身上来了?这就是你的不对了。 对呀!根据职责分明的设计原则,人家UserService就只该管用户管理部分的业务逻辑,你老让它干别人干的事,它当然不高兴了!那该怎么拌?凉拌?

事件机制

Spring给我们提供了一个方案,利用事件机制来实现解耦。也就是观察者设计模式,设置监听器来监听userService的注册事件(同时,我们可以很自然地将userService理解成了事件发布者),一旦userService注册了,发送一个完成事件,监听器就完成相应的邮箱、短信发送工作(同时,我们也可以很自然地将发送邮件、发送短信理解成我们的事件源)。这样userService就不用管别人的事了,只需要在完成注册功能时候,当下老大,号令手下(监听器),让它完成短信、邮箱的发送工作。

spring的事件通信常按下列流程进行,事件发布者发布事件源 进行广播,事件监听者监听到了事件,从而进行处理,我们涉及到三个主要对象:事件发布者、事件源、事件监听器。根据这三个对象,我们来配置我们的注册事件实例

定义事件源

利用事件通信的第一步往往便是定义我们的事件。在spring中,所有事件都必须扩展抽象类ApplicationEvent,同时将事件源作为构造函数参数,在这里,我们定义一个用户注册完成事件

定义事件监听者

监听到用户注册完成的事件后,进行业务处理;类似观察者模式;这里我们可以定义两个事件监听器,一个是ToEmailListener 和 ToPhoneListener,一个用来发送邮件,一个用来发送短信。从业务上看就是用户注册完成后,此2个监听器得到事件后,触发发送邮件和短信业务。监听器需要实现ApplicationListener接口,看如下代码

事件监听者

ToEmailListener实现了ApplicationListener接口,监听用户注册完成事件,重写了onApplicationEvent(UserRegisteredEvent event)方法,在此方法中实现发送邮件业务,记得需要@Component注入到spring容器中。

事件监听者

ToPhoneListener实现了ApplicationListener接口,监听用户注册完成事件,重写了onApplicationEvent(UserRegisteredEvent event)方法,在此方法中实现发送短信业务,记得需要@Component注入到spring容器中。

事件发布者

在用户注册完成业务中,实现事件发布,如下伪代码

事件发布者

请求地址调用

用户注册

启动访问http://localhost:8081/user/register,查看日志

达到业务目的,实现了业务解耦,将来如果还有其他业务是在用户注册完成后进行处理,就不需要麻烦用户注册模块的小伙伴了,自行添加一个监听类实现。不过这个有个注意点,处理其他业务的时候,是否需要相应的属性,如发送邮件的时候,需要指导这个用户的邮箱地址;发送短信就需要知道用户的手机号码;这些属性是需要用户注册模块那边进行赋值的。需要其他业务还需要另外的属性值,那就需要麻烦注册模块的开发人员加上。一般情况下我们都会把用户常用的属性给开放出来,供其他业务使用。

异步处理

其实上面的实现,还存在严重的问题,我们看一下启动的效果日志,我们发现 注册成功这个日志,是同一个线程进行处理的,一定要等发送邮件和发送短信这2个业务完成后,才会执行,这也就代表了这个事件机制是同步的,也就是用户注册完成后,一定要等到其他监听器的业务完成后,才会返回。这个是不合理的,因为用户注册在这一刻就完成了,我不需要知道有没有其他业务进行业务处理,也不需要等待他们业务处理完成,注册业务才能够返回。那我们应该怎么处理呢?其实比较简单就是在监听类上加入一个@Async注解,这个我们之前课程介绍过,能够实现异步处理

这样就不需要等待其他业务的处理了,我们也发现是不同的线程进行处理业务的,这样就达到了我们真正的解耦业务。

当然这个属于单应用,或者不复杂的应用,可以采用这种方式。如果对于微服务的业务,比较复杂,以及不同的业务需求,解耦方案可以利用其他方案,但原理是一样的。比如:MQ中间件进行业务解耦。


原文链接:

www.toutiao.com/i6665467827467584013/

最近热文阅读:

1、我是如何用Redis做实时订阅推送的

2、面试必备:Zookeeper选举算法原理你知道吗?

3、面试题:群聊消息的已读未读设计

4、20年开发经验总结,“设计模型”才是架构设计的魂!

5、为什么架构师一定要懂“故障隔离”?

6、我是一条DQL

7、你真的理解零拷贝吗?

8、90%程序员面试都用得上的索引优化手册

关注公众号,你想要的Java都在这里!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存